﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Security.Principal;
using System.Web;
using System.Web.Profile;
using System.Data;
using System.IO;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Data.SqlClient;
using Vit.Common.Providers;
using Vit.Common.Helpers;
using Vit.Web;
using Vit.Web.Models;
using Vit.Web.Helpers;
using Vit.Web.Extensions;
using Vit.Web.Providers;

namespace Vit.AdminModule.Areas.Admin.Providers
{
    public class SqlNavigationProvider : Vit.Web.Providers.INavigationProvider
    {
        private readonly string MenuFileName = "menu.xml";
        private ICacheProvider cache;
        private IMembershipProvider membership;
        private WebProvidersDb db;

        public SqlNavigationProvider(ICacheProvider cache, IMembershipProvider membership, WebProvidersDb db)
        {
            this.cache = cache;
            this.membership = membership;
            this.db = db;
        }

        private List<XElement> LoadNavigationItems()
        {
            var currentSite = PortalContext.Current.Site;
            string key = string.Format("Menu:{0}", currentSite.ID);
            if (cache != null && cache.Contains(key))
                return cache.GetData(key) as List<XElement>;

            List<XElement> roots = new List<XElement>();
            foreach (var menuFile in currentSite.ConfigurationFiles.Where(o => o.Name.Equals(MenuFileName, StringComparison.OrdinalIgnoreCase)))
            {
                XDocument rootDoc = XDocument.Load(menuFile.FullName);
                roots.Add(rootDoc.Root);
            }

            if (cache != null)
                cache.Add(key, roots);

            return roots;
        }

        private XElement FindNavigationItemByAttribute(string attrName, string attrValue)
        {
            List<XElement> roots = LoadNavigationItems();
            foreach (XElement root in roots)
            {
                XElement ele = root.XPathSelectElement(string.Format(".//menu[translate(@{0},'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='{1}']", attrName, attrValue.ToLower()));
                if (ele != null)
                    return ele;
            }
            return null;
        }

        private NavigationItem ParseNavigationItem(XElement ele)
        {
            NavigationItem menu = new NavigationItem()
            {
                Name = ele.Attribute("name").Value,
                Url = ele.Attribute("url").Value,
                //ImageUrl = ele.Attribute("imgUrl").Value,
                //Tooltip = ele.Attribute("tooltip").Value,
                //Description = ele.Attribute("description").Value,
                Target = ele.Attribute("target") == null ? null : ele.Attribute("target").Value,
                SelectedPattern = ele.Attribute("selectedPattern").Value,
                PermissionPattern = ele.Attribute("permissionPattern").Value,
                Items = new List<NavigationItem>()
            };

            var localeAttr = ele.Document.Root.Attribute("locale");
            if (localeAttr != null)
            {
                menu.Caption = Locale.GetString(localeAttr.Value, menu.Name);
                menu.ImageUrl = Locale.GetString(localeAttr.Value, menu.Name + "_ImageUrl");
                menu.Tooltip = Locale.GetString(localeAttr.Value, menu.Name + "_Tooltip");
                menu.Description = Locale.GetString(localeAttr.Value, menu.Name + "_Description");

                if (menu.ImageUrl == menu.Name + "_ImageUrl")
                    menu.ImageUrl = null;
                if (menu.Tooltip == menu.Name + "_Tooltip")
                    menu.Tooltip = menu.Caption;
                if (menu.Description == menu.Name + "_Description")
                    menu.Description = menu.Caption;
            }
            else
            {
                menu.Caption = menu.Name;
            }

            return menu;
        }

        #region INavigationService Members

        public IQueryable<NavigationItem> GetDefaultGroupNavigationItems()
        {
            string key = "DefaultMenu";
            if (cache != null && cache.Contains(key))
            {
                var cachedResult = cache.GetData(key) as IQueryable<NavigationItem>;
                if (cachedResult != null && cachedResult.Count() > 0)
                    return cachedResult;
            }

            List<XElement> roots = LoadNavigationItems();
            var menus = MenuHelper.ParseMenuItems(roots, ParseNavigationItem);

            if (cache != null)
                cache.Add(key, menus);

            return menus.AsQueryable();
        }

        //public IQueryable<NavigationGroup> GetAllNavigationGroup()
        //{
        //    return db.NavigationGroups;
        //}

        public bool CreateNavigationGroup(string groupName)
        {
            NavigationGroup group = new NavigationGroup()
            {
                Name = groupName
            };

            db.NavigationGroups.Add(group);
            int result = db.SaveChanges();
            return result > 0;
        }

        public bool DeleteNavigationGroup(string groupName)
        {
            var group = db.NavigationGroups.FirstOrDefault(o => o.Name == groupName);
            if (group != null)
            {
                db.NavigationGroups.Remove(group);
                int result = db.SaveChanges();
                return result > 0;
            }
            return false;
        }

        public bool CopyAllNavigationItemToAnotherGroup(string fromGroup, string toGroup)
        {
            var fgroup = db.NavigationGroups.FirstOrDefault(o => o.Name == fromGroup);
            if (fgroup == null)
                return false;
            var tgroup = db.NavigationGroups.FirstOrDefault(o => o.Name == toGroup);
            if (tgroup == null)
            {
                tgroup = new NavigationGroup() { Name = toGroup };
                db.NavigationGroups.Add(tgroup);
            }
            tgroup.Items = fgroup.Items;
            int result = db.SaveChanges();
            return result > 0;
        }

        public IQueryable<NavigationItem> GetNavigationItemsByGroup(string groupName)
        {
            if (string.IsNullOrEmpty(groupName))
                return GetDefaultGroupNavigationItems();

            var group = db.NavigationGroups.FirstOrDefault(o => o.Name == groupName);
            if (group != null)
            {
                return group.Items.AsQueryable();
            }
            return null;
        }

        //public NavigationItem GetNavigationByName(string name)
        //{
        //    try
        //    {
        //        var items = GetDefaultGroupNavigationItems();
        //        var findItems = HierarchyHelper.FindDescendants<NavigationItem>(items, o => o.Items, o => o.Name == name);
        //        return findItems.FirstOrDefault();
        //        //XElement ele = FindNavigationItemByAttribute("name", name);
        //        //if (ele != null)
        //        //{
        //        //    NavigationItem item = ParseNavigationItem(ele, true);
        //        //    return item;
        //        //}
        //    }
        //    catch
        //    {
        //        throw;
        //    }
        //}

        //public NavigationItem GetNavigationByUrl(string url)
        //{
        //    try
        //    {
        //        var items = GetDefaultGroupNavigationItems();
        //        var findItems = HierarchyHelper.FindDescendants<NavigationItem>(items, o => o.Items, o => o.Url == url);
        //        return findItems.FirstOrDefault();
        //        //XElement ele = FindNavigationItemByAttribute("url", url);
        //        //if (ele != null)
        //        //{
        //        //    NavigationItem item = ParseNavigationItem(ele, true);
        //        //    return item;
        //        //}
        //    }
        //    catch
        //    {
        //        throw;
        //    }
        //}

        //public IQueryable<NavigationItem> GetUserAccessableNavigationItems(string userName, string groupName)
        //{
        //    if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(groupName))
        //        return GetDefaultGroupNavigationItems();

        //    string key = string.Format("User:{0};Group:{1}", userName, groupName);
        //    if (cache != null)
        //        return cache[key] as IQueryable<NavigationItem>;

        //    var items = GetNavigationItemsByGroup(groupName);
        //    if (items != null && membership != null)
        //    {
        //        var query = items.Where(o => membership.CanUserAccess(userName, o.PermissionPattern));
        //        if (cache != null)
        //            cache.Add(key, query);

        //        return query;
        //    }

        //    if (cache != null && items != null)
        //        cache.Add(key, items);

        //    return items;
        //}

        //public IQueryable<NavigationItem> GetRoleAccessableNavigationItems(string roleName, string groupName)
        //{
        //    if (string.IsNullOrEmpty(roleName) || string.IsNullOrEmpty(groupName))
        //        return GetDefaultGroupNavigationItems();

        //    string key = string.Format("Role:{0};Group:{1}", roleName, groupName);
        //    if (cache != null)
        //        return cache[key] as IQueryable<NavigationItem>;

        //    var items = GetNavigationItemsByGroup(groupName);
        //    if (items != null && membership != null)
        //    {
        //        var query = items.Where(o => membership.CanRoleAccess(roleName, o.PermissionPattern));
        //        if (cache != null)
        //            cache.Add(key, query);

        //        return query;
        //    }

        //    if (cache != null && items != null)
        //        cache.Add(key, items);

        //    return items;
        //}

        #endregion

        #region IProvider Members

        public string Name
        {
            get { return "SqlNavigationProvider"; }
        }

        #endregion
    }
}
